/*
 * Galaxium Messenger
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;

using Anculus.Core;

using Galaxium.Core;

namespace Galaxium.Protocol.Msn
{
	public class MessengerPlusSplitter : IMessageSplitter
	{
		static Regex _regexMsgPlus = new Regex (@"\[(/?)([a-zA-Z0-9#]*)(=([a-zA-Z0-9#]*))?]", RegexOptions.Compiled);
		
		int _bold = 0, _italic = 0, _underline = 0, _strikethrough = 0;
		List<int> _foreColors = new List<int> ();
		List<int> _backColors = new List<int> ();
		List<int> _fontSizes = new List<int> ();
		
		public List<ITextChunk> SplitMessage (string message, ITextStyle style, IEntity entity, List<IEmoticon> customEmoticons)
		{
			// Mode 0 = Display formatting, 1 = Hide formatting, 2 = Ignore formatting
			int mode = Configuration.Protocol.Section["MSN"].GetInt ("PlusFormatMode", 0);
			bool setStyle = mode != 1;
			int pos = 0;
			List<ITextChunk> chunks = new List<ITextChunk> ();
			
			if (mode > 1)
			{
				// Ignore plus! formatting
				
				chunks.Add (new TextChunk (style, TextChunkType.Text, message));
				return chunks;
			}
			
			foreach (Match match in _regexMsgPlus.Matches (message))
			{
				string name = match.Groups[2].Value.ToLower ();
				string param = match.Groups[4].Value;
				bool closing = match.Groups[1].Value == "/";
				
				if ((name != "b") && (name != "i") && (name != "u") &&
				    (name != "s") && (name != "c") && (name != "a"))
					continue;
				
				AddText (message, style, setStyle, pos, match.Index, ref chunks);
				
				if (setStyle)
				{
					if (!closing)
					{
						if (name.Equals ("b", StringComparison.InvariantCultureIgnoreCase))
							_bold++;
						else if (name.Equals ("i", StringComparison.InvariantCultureIgnoreCase))
							_italic++;
						else if (name.Equals ("u", StringComparison.InvariantCultureIgnoreCase))
							_underline++;
						else if (name.Equals ("s", StringComparison.InvariantCultureIgnoreCase))
							_strikethrough++;
						else if (name.Equals ("c", StringComparison.InvariantCultureIgnoreCase))
							_foreColors.Add (GetColor (param));
						else if (name.Equals ("a", StringComparison.InvariantCultureIgnoreCase))
							_backColors.Add (GetColor (param));
					}
					else
					{
						if (name.Equals ("b", StringComparison.InvariantCultureIgnoreCase))
							_bold = Math.Max (_bold - 1, 0);
						else if (name.Equals ("i", StringComparison.InvariantCultureIgnoreCase))
							_italic = Math.Max (_italic - 1, 0);
						else if (name.Equals ("u", StringComparison.InvariantCultureIgnoreCase))
							_underline = Math.Max (_underline - 1, 0);
						else if (name.Equals ("s", StringComparison.InvariantCultureIgnoreCase))
							_strikethrough = Math.Max (_strikethrough - 1, 0);
						else if (name.Equals ("c", StringComparison.InvariantCultureIgnoreCase) && (_foreColors.Count > 0))
							_foreColors.RemoveAt (_foreColors.Count - 1);
						else if (name.Equals ("a", StringComparison.InvariantCultureIgnoreCase) && (_backColors.Count > 0))
							_backColors.RemoveAt (_backColors.Count - 1);
					}
				}
				
				pos = match.Index + match.Length;
				
				//Log.Debug ("Matched '{0}', param '{1}'{2}", name, param, closing ? " (closing)" : string.Empty);
			}
			
			AddText (message, style, setStyle, pos, message.Length, ref chunks);
			
			_foreColors.Clear ();
			_backColors.Clear ();
			_fontSizes.Clear ();
			
			return chunks;
		}
		
		void AddText (string msg, ITextStyle style, bool setStyle, int pos, int index, ref List<ITextChunk> chunks)
		{
			if (pos >= index)
				return;
			
			string txt = msg.Substring (pos, index - pos);
			ITextStyle txtStyle = style.Clone () as ITextStyle;
			
			if (setStyle)
			{
				txtStyle.Bold |= _bold > 0;
				txtStyle.Italic |= _italic > 0;
				txtStyle.Strikethrough |= _strikethrough > 0;
				txtStyle.Underline |= _underline > 0;
				
				if (_foreColors.Count > 0)
					txtStyle.ForeColor = _foreColors[_foreColors.Count - 1];
				if (_backColors.Count > 0)
					txtStyle.BackColor = _backColors[_backColors.Count - 1];
			}
			
			ITextChunk chunk = new TextChunk (txtStyle, TextChunkType.Text, txt);
			chunks.Add (chunk);
		}
		
		public static int GetColor (string param)
		{
			param = param.Trim ();
			
			if (param.StartsWith ("#"))
			{
				param = param.Substring (1);
				
				if (param.Length == 3)
				{
					param = param.Substring (0, 1) + param.Substring (0, 1) +
							param.Substring (1, 1) + param.Substring (1, 1) +
							param.Substring (2, 1) + param.Substring (2, 1);
				}
				
				int ret;
				if (int.TryParse (param, NumberStyles.HexNumber, null, out ret))
					return ret;
				
				return 0;
			}
			
			int col;
			if (!int.TryParse (param, out col))
				col = 1;
			
			return GetColor (col);
		}
		
		public static int GetColor (int col)
		{
			if (col == 0)
				return 0xffffff;
			if (col == 1)
				return 0x000000;
			if (col == 2)
				return 0x00007D;
			if (col == 3)
				return 0x009100;
			if (col == 4)
				return 0xFF0000;
			if (col == 5)
				return 0x7D0000;
			if (col == 6)
				return 0x9A009A;
			if (col == 7)
				return 0xFC7D00;
			if (col == 8)
				return 0xFFFF00;
			if (col == 9)
				return 0x00FC00;
			if (col == 10)
				return 0x009191;
			if (col == 11)
				return 0x00FFFF;
			if (col == 12)
				return 0x1E1EFC;
			if (col == 13)
				return 0xFF00FF;
			if (col == 14)
				return 0x7D7D7D;
			if (col == 15)
				return 0xD2D2D2;
			if (col == 16)
				return 0xE7E6E4;
			if (col == 17)
				return 0xcfcdd0;
			if (col == 18)
				return 0xffdea4;
			if (col == 19)
				return 0xffaeb9;
			if (col == 20)
				return 0xffa8ff;
			if (col == 21)
				return 0xc1b4fc;
			if (col == 22)
				return 0xbafbe5;
			if (col == 23)
				return 0xccffa3;
			if (col == 24)
				return 0xfafda2;
			if (col == 25)
				return 0xb6b4b7;
			if (col == 26)
				return 0xa2a0a1;
			if (col == 27)
				return 0xf9c152;
			if (col == 28)
				return 0xff6d66;
			if (col == 29)
				return 0xff62ff;
			if (col == 30)
				return 0x6c6cff;
			if (col == 31)
				return 0x68ffc3;
			if (col == 32)
				return 0x000000;
			if (col == 33)
				return 0xf9ff57;
			if (col == 34)
				return 0x858482;
			if (col == 35)
				return 0x6e6d7b;
			if (col == 36)
				return 0xffa01e;
			if (col == 37)
				return 0xF92411;
			if (col == 38)
				return 0xFF1EFF;
			if (col == 39)
				return 0x1E29FF;
			if (col == 40)
				return 0x7dffa5;
			if (col == 41)
				return 0x60f913;
			if (col == 42)
				return 0xfff813;
			if (col == 43)
				return 0x5e6464;
			if (col == 44)
				return 0x4b494c;
			if (col == 45)
				return 0xd98812;
			if (col == 46)	
				return 0xeb0505;
			if (col == 47)	
				return 0xde00de;
			if (col == 48)	
				return 0x0000d3;
			if (col == 49)	
				return 0x03cc88;
			if (col == 50)	
				return 0x59d80d;
			if (col == 51)	
				return 0xd4c804;
			if (col == 52)	
				return 0x333335;
			if (col == 53)	
				return 0x18171c;
			if (col == 54)	
				return 0x944e00;
			if (col == 55)	
				return 0x9b0008;
			if (col == 56)	
				return 0x980299;
			if (col == 57)	
				return 0x01038c;
			if (col == 58)	
				return 0x01885f;
			if (col == 59)	
				return 0x389600;
			if (col == 60)	
				return 0x9a9e15;
			if (col == 61)
				return 0x473400;
			if (col == 62)	
				return 0x4d0000;
			if (col == 63)	
				return 0x5f0162;
			if (col == 64)	
				return 0x000047;
			if (col == 65)	
				return 0x06502f;
			if (col == 66)	
				return 0x1c5300;
			if (col == 67)	
				return 0x544d05;
			
			return 0x000000;
		}
	}
}
